package cn.wolfcode.luowowo.search.service.impl;

import cn.wolfcode.luowowo.article.domain.Destination;
import cn.wolfcode.luowowo.article.service.IDestinationService;
import cn.wolfcode.luowowo.search.query.IndexSearchQuery;
import cn.wolfcode.luowowo.search.query.SearchQueryObject;
import cn.wolfcode.luowowo.search.repository.StrategyTemplateRepository;
import cn.wolfcode.luowowo.search.service.IStrategyTemplateSearchService;
import cn.wolfcode.luowowo.search.service.SearchQueryService;
import cn.wolfcode.luowowo.search.template.StrategyTemplate;
import cn.wolfcode.luowowo.search.template.UserInfoTemplate;
import cn.wolfcode.luowowo.search.vo.StaticVo;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.composite.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;

import java.io.IOException;
import java.util.*;

/**
 * @author 猫教授
 * @date 2019/8/17 20:03
 */
@Service
public class StrategyTemplateSearchServiceImpl implements IStrategyTemplateSearchService {
    //操作se搜索引擎的共有三个操作方式,分别con底层到上层
    //第一种,是repository接口
    @Autowired
    private StrategyTemplateRepository repository;
    //第二种是template
    @Autowired
    private ElasticsearchTemplate template;
    //第三种是最底层的
    @Autowired
    private TransportClient client;

    @Reference
    private IDestinationService destinationService;
    @Autowired
    private SearchQueryService searchQueryService;
    @Override
    public void save(StrategyTemplate strategyTemplate) {
        repository.save(strategyTemplate);
    }


    /**
     * @param id
     * @param name
     * @return GET /luowowo_strategy/strategy/_search
     * {
     * "size": 0,
     * "aggs": {
     * "grpoupselect": {
     * "composite": {
     * "sources": [
     * {
     * "id": {
     * "terms": {
     * "field": "themeId"
     * }
     * }
     * },{
     * "name":{
     * "terms": {
     * "field": "themeName"
     * }
     * }
     * }
     * ]
     * }
     * }
     * }
     * }
     */
    @Override
    public List<Map<String, Object>> selectGroupByField(String id, String name) throws IOException {
        List<Map<String, Object>> data = new ArrayList<>();
        List<StaticVo> themeList = QueryGroupBy2Fieid(id, name);

        List<StaticVo> sublist = null;
        //第二个就是截取前面10个
        if (themeList.size() > 10) {
            sublist = themeList.subList(0, 10);
        } else {
            sublist = themeList.subList(0, themeList.size());
        }

        //主题加进那个列表里面
        for (StaticVo vo : sublist) {
            Map<String, Object> map = new HashMap<>();
            map.put("theme", vo);
            //然后调用内部方法查询对应地点
            Set<StaticVo> dests = getdest(vo);
            //第三个完善的点就去去重,直接使用set
            map.put("dests", dests);
            data.add(map);
        }
        return data;
    }

    @Override
    public List<StaticVo> selectcChinaGroup(String id, String name) {
        List<StaticVo> staticVos = QueryGroupBy2Fieid(id, name);
        List<StaticVo> chinas = new ArrayList<>();
        for (StaticVo staticVo : staticVos) {
            ArrayList<Destination> list = new ArrayList<>();
            getToasts(staticVo.getId(), list);
            Long id1 = list.get(list.size() - 1).getId();
            if (id1 == 1) {
                chinas.add(staticVo);
            }
        }
        return chinas;
    }

    @Override
    public List<StaticVo> selectcAbroadsGroup(String countryId, String countryName) {
        List<StaticVo> staticVos = QueryGroupBy2Fieid(countryId, countryName);
        List<StaticVo> abroads = new ArrayList<>();
        for (StaticVo staticVo : staticVos) {
            ArrayList<Destination> list = new ArrayList<>();
            getToasts(staticVo.getId(), list);
            Long id1 = list.get(list.size() - 1).getId();
            if (id1 != 1) {
                abroads.add(staticVo);
            }
        }
        return abroads;
    }

    @Override
    public List<StaticVo> selectThemeGroup(String themeId, String themeName) {
        return QueryGroupBy2Fieid(themeId, themeName);
    }

    @Override
    public List<StaticVo> SearchQueryGroup(String one, String two, int type) {
        switch (type) {
            case SearchQueryObject.CONDITION_TYPE_ABROAD:
                return selectcAbroadsGroup(one, two);
            case SearchQueryObject.CONDITION_TYPE_UN_ABROAD:
                return selectcChinaGroup(one,two);
            case SearchQueryObject.CONDITION_TYPE_THEME:
                return selectThemeGroup(one,two);
        }
        return new ArrayList<>();
    }

    @Override
    public Page<StrategyTemplate> selectStrategyByQo(SearchQueryObject qo) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //指定查询具体哪个表
        builder.withIndices(StrategyTemplate.INDEX_NAME);
        builder.withTypes(StrategyTemplate.TYPE_NAME);
        //分页排序
        builder.withPageable(qo.getPageable());
        switch (qo.getType()){
            case SearchQueryObject.CONDITION_TYPE_ABROAD:
                builder.withQuery(QueryBuilders.matchQuery("countryId",qo.getTypeValue()));break;
            case SearchQueryObject.CONDITION_TYPE_UN_ABROAD:
                builder.withQuery(QueryBuilders.matchQuery("provinceId",qo.getTypeValue()));break;
            case SearchQueryObject.CONDITION_TYPE_THEME:
                builder.withQuery(QueryBuilders.matchQuery("themeId",qo.getTypeValue()));break;
        }
        return repository.search(builder.build());
    }

    @Override
    public List<StrategyTemplate> findByDestName(String keyword) {



        return repository.findByDestName(keyword);
    }

    @Override
    public AggregatedPage<StrategyTemplate> selectByKeyword(IndexSearchQuery qo, String... fieldName) {
        return searchQueryService.selectByKeyword(qo,"<span style='color:red;'>","</span>",StrategyTemplate.class,StrategyTemplate.INDEX_NAME,StrategyTemplate.TYPE_NAME,fieldName);

    }


    /**
     * 抽离分组的通用方法
     */
    private List<StaticVo> QueryGroupBy2Fieid(String id, String name) {

        //首先第一步我们先建立一个最外围的花括号
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        /**
         * 一定要排除那个其他索引库,不然会直接查询其他索引库的
         *
         */
        builder.withIndices(StrategyTemplate.INDEX_NAME);
        builder.withTypes(StrategyTemplate.TYPE_NAME);
        //第二步我们建立composite模块
        List<CompositeValuesSourceBuilder<?>> sources = new ArrayList<>();
        //第三步我们建立分组
        //第一个分组对象
        TermsValuesSourceBuilder idSource = new TermsValuesSourceBuilder("id");
        //是否忽略分组
        idSource.missingBucket(true);
        //添加分组字段
        idSource.field(id);
        sources.add(idSource);
        TermsValuesSourceBuilder nameSource = new TermsValuesSourceBuilder("name");
        //是否忽略分组
        nameSource.missingBucket(true);
        //添加分组字段
        nameSource.field(name);
        sources.add(nameSource);
        CompositeAggregationBuilder composi = new CompositeAggregationBuilder("selectBytheme", sources);
        //然后再把那个分组的需求加进buidler查询对象
        builder.addAggregation(composi);
        //然后进行查询并解析他的结果
        Aggregations aggregations = template.query(builder.build(), response -> {
            return response.getAggregations();
        });
        ArrayList<StaticVo> themeList = new ArrayList();
        InternalComposite selectBytheme = aggregations.get("selectBytheme");
        for (CompositeAggregation.Bucket group : selectBytheme.getBuckets()) {
            StaticVo staticVo = new StaticVo();
            System.out.println(group.getKey());
            /**
             * 这里要注意对为空的进行排除,第一个就会出现为空的情况
             */
            if (group.getKey().get("id") != null && group.getKey().get("name") != null) {
                staticVo.setId(Long.parseLong(group.getKey().get("id").toString()));
                staticVo.setName(group.getKey().get("name").toString());
                staticVo.setCount(group.getDocCount());
                themeList.add(staticVo);
            }
        }
        //第一个完善的点排序
        themeList.sort((StaticVo v1, StaticVo v2) -> {
            return Integer.parseInt(v2.getCount() - v1.getCount() + "");
        });
        return themeList;
    }


    //写一个内部方法用来另外查询附带的对应的地点数据
    private Set<StaticVo> getdest(StaticVo themevo) {
        Set<StaticVo> dest = new HashSet<>();
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("themeId", themevo.getId())).must(QueryBuilders.matchQuery("themeName", themevo.getName())));
        Page<StrategyTemplate> page = repository.search(builder.build());
        List<StrategyTemplate> content = page.getContent();
        for (StrategyTemplate strategyTemplate : content) {
            StaticVo staticVo = new StaticVo();
            staticVo.setId(strategyTemplate.getDestId());
            staticVo.setName(strategyTemplate.getDestName());
            dest.add(staticVo);
        }
        return dest;

    }

    /**
     * 内部方法用来迭代吐丝的
     *
     * @param destinationId
     * @param toasts
     */
    private void getToasts(Long destinationId, ArrayList toasts) {
        Destination destination = destinationService.selecOne(destinationId);
        toasts.add(destination);
        if (destination.getParent() != null) {
            getToasts(destination.getParent().getId(), toasts);
        }
    }

}
